#! lua
-- Gavin Wraith  13/12/2007, 11/10/2015
-- Display csv files
(getmetatable "").__call = string.format
-- load required libraries
local lpeg, riscos = require "lpeg", require "riscos"

-- error messages
local err_file = "Cannot open %s"
local err_ftype = "%s has wrong filetype"
local err_content = "%s not a CSV file"
local err_template = "Cannot open template file"
local err_out = "Cannot write output"
local err_empty = "%s has no records"

-- use libraries
local open in io
local execute in os
local filetype in riscos
local concat in table

-- lpeg
local csv
do
 local C, Cs, Ct, P, S in lpeg
 local space = (S " \t")^0
 local dq, comma, nl = P '"', P ',', '\n'
 local unquoted = C ((1 - (dq + comma + nl))^0)
 local quoted = space*dq*Cs (((dq*dq)/'"' + (1 - dq))^0)*dq*space
 local field = quoted + unquoted
 local record = Ct (field*(comma*field)^0)
 csv = (Ct ((record*nl)^0))
end -- do

-- read file
local text,leaf, file
do
  file = arg[1]
 leaf = file:match ("[^%.]+$")
 assert (filetype (file) == 0xdfe, err_ftype (leaf))
 local f = assert (open (file,"r"), err_file (leaf))
 text = f:read "*all"
 f:close ( )
end -- do

-- match
local data = csv:match (text)
assert (data and type (data) == "table", err_content (leaf))
assert(#data > 0, err_empty (leaf))

-- equalize records
do
local n, k = #(data[1])
for i = 2, #data do
 k = #(data[i])
 n = (k > n) and k or n
end -- for
for _, row in ipairs (data) do
   while #row < n do row[#row + 1] = "" end -- while
end -- for
end -- do


-- read in page template
local template
do
 local file = "<csv2html$dir>.out.template"
 local f = assert (open (file,"r"), err_template)
 template = f:read "*all"
 f:close ( )
end -- do

-- make page
local clean
do
 local catchall = "(.)"
 local entify = \ (c)
       local n, fmts = c:byte ( ),"&#%s;"
       => (n > 127 and fmts (n) or c)
       end -- function
  clean = \ (s)
          s = s:gsub ("&", "&amp;")
          s = s:gsub ("<", "&lt;")
          s = s:gsub (">", "&gt;")
          => s:gsub (catchall, entify)
         end -- function
end -- do

local mktable = \ (d)
   local p = { }
   for i, row in ipairs (d) do
     p[#p + 1] = ('<tr class="row%d">\n') (i%2)
     for j,v in ipairs (row) do
       p[#p + 1] = ('<td class="row%dcol%d">') (i%2,j%2)
       p[#p + 1] = clean (v)
       p[#p + 1] = '</td>\n'
     end -- for
     p[#p + 1] = '</tr>\n'
   end -- for
   => concat (p)
   end -- function

local page = template (leaf, leaf, mktable (data))

-- output page
local out
local ext = "/csv$"
if file:match (ext) then
  out = file:gsub (ext, "/html")
else
 out = file .. "/html"
end -- if
local outdir = file:gsub ("%.[^%.]+$", "")
local cpycmd = "copy %s %s A~C~DF~LN~PQ~R~S~sT~V"
execute (cpycmd ("<csv2html$dir>.out.style/css", outdir..".style/css"))
do
 local f = assert (open (out,"w"), err_out)
 f:write (page)
 f:close ( )
end -- do
execute ("settype "..out.." html")
execute ("filer_run "..out)
